#include <SessionManagerI.h>

class RenderSessionI : public Yafridng::RenderSession, public IceUtil::Mutex
{
 public:
  RenderSessionI(const Glacier2::SessionControlPrx& control,
		 const Yafridng::YafridngNodeManagerPrx& nodeManager) :
   _control(control),
   _nodeManager(nodeManager),
   _allocated(0)
      {
      }
  
  ~RenderSessionI()
    {
    }
  
  virtual void keepAlive(const Ice::Current&)
  {
  }
  
  virtual YafridngRendererPrx create(const ::Ice::Int renderEngine,
				     const ::std::string& scene, 
				     const Ice::Current& c)
  {
    Lock sync(*this);
    try{
      //if(_allocated < 3){
	YafridngRendererFactoryPrx allocated = _nodeManager->allocateNode();    
	YafridngRendererPrx renderer = allocated->createRenderer(renderEngine, scene);
	_factories.push_back(allocated);
	_renderers.push_back(renderer);
	Ice::IdentitySeq ids;
	Ice::StringSeq category;
	ids.push_back(renderer->ice_getIdentity());
	_allocated++;
	/*category.push_back(c.id.name);
	  _control->identities()->add(ids);
	  _control->categories()->add(category);*/
	return renderer;
	//}
	/*else{
	NoMoreNodesException ex;
	throw ex;
	}*/
    }
    catch(Yafridng::NoMoreNodesException& ex){
      throw ex;
    }
  }

  virtual void addNode(const Yafridng::YafridngRendererFactoryPrx& node,
		       const Ice::Current& c)
  {
    _nodeManager->addNode(node);
  }

  virtual void destroy(const Ice::Current& c)
  {
    Lock sync(*this);
    //Deallocating all used objects
    for(int i = 0; i < _renderers.size(); i++){
      try
	{
	  _renderers.at(i)->flush();
	}
      catch(const Ice::Exception& ex)
	{
	  //Empty Exception
	}
    }

    for(int i = 0; i < _factories.size(); i++)
      _nodeManager->releaseNode(_factories.at(i));

    try
      {
	c.adapter->remove(c.id);
	cout << "\n\nSESSION DESTROYED\n\n" << endl;
      }
    catch(const Ice::NotRegisteredException&)
      {
	return;
      }
    
    _factories.clear();
    /*Ice::IdentitySeq ids;
    ids.push_back(c.id);
    _control->identities()->remove(ids);*/
  }

  /*  void allocationFailed()
  {
    Lock lock(*this);
    --_allocated;
    assert(_allocated >= 0);
    }*/
  
 private:
  const Glacier2::SessionControlPrx _control;
  Yafridng::YafridngNodeManagerPrx _nodeManager;
  vector<Yafridng::YafridngRendererFactoryPrx> _factories;
  vector<Yafridng::YafridngRendererPrx> _renderers;
  int _allocated;
};

typedef IceUtil::Handle<RenderSessionI> RenderSessionIPtr;

SessionManagerI::SessionManagerI(const Glacier2::SSLSessionManagerPrx& manager) :
  _manager(manager)
{
}

SessionManagerI::~SessionManagerI()
{
}

Glacier2::SessionPrx SessionManagerI::create(const Glacier2::SSLInfo& info,
			const Glacier2::SessionControlPrx& control,
			const Ice::Current& c)
{
  Lock sync(*this);
  //Finishing any dead session
  vector<Glacier2::SessionPrx>::iterator p = _sessions.begin();
  while(p != _sessions.end())
    {
      try
	{
	  (*p)->ice_ping();
	  ++p;
	}
      catch(const Ice::Exception&)
	{
	  p = _sessions.erase(p);
	}
    }
  
  Ice::CommunicatorPtr communicator = c.adapter->getCommunicator();
  Ice::Trace trace(communicator->getLogger(), "SessionManagerI");

  Yafridng::YafridngNodeManagerPrx nodeManager = Yafridng::YafridngNodeManagerPrx::
    checkedCast(communicator->stringToProxy("YafridngNodeManager@YafridngAdapter"));

  Glacier2::SessionPrx interposed = Glacier2::SessionPrx::uncheckedCast
    (c.adapter->addWithUUID(new RenderSessionI(control, nodeManager)));

  _sessions.push_back(interposed);
  Glacier2::IdentitySetPrx identities = control->identities();
  Ice::IdentitySeq ids;
  /*  ids.push_back(interposed->ice_getIdentity());
  identities->add(ids);
  ids.clear();
  //ids.push_back(nodeManager->ice_getIdentity());
  //identities->remove(ids);*/
  trace << " interposed: " << communicator->proxyToString(interposed);
  return interposed;
}
